package com.swingson.properties.specificclass_impl;

import com.swingson.Swingson;
import com.swingson.SwingsonGui;
import com.swingson.jsonparser.JsonElement;
import com.swingson.other.ConditionAndAction;
import com.swingson.other.MethodExecutor;
import com.swingson.properties.AbstractAssignMethodPropertyProcessor;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;

/**
 * @author sad
 */
public class KeyActionPropertyProcessor extends AbstractAssignMethodPropertyProcessor {

    public static final String keyPressed = "keyPressed";
    public static final String keyTyped = "keyTyped";
    public static final String keyReleased = "keyReleased";

    static List<Class[]> argumentsVariants = new ArrayList<Class[]>() {
        {
            add(new Class[]{char.class});//key char
            add(new Class[]{char.class, int.class});//key char, key code
            add(new Class[]{char.class, int.class, int.class});//key char, key code, modifiers
            add(new Class[]{KeyEvent.class});

        }
    };

    @Override
    protected String getName() {
        return "Key Event Listener";
    }

    @Override
    protected List<Class[]> methodArgumentsVariants() {
        return argumentsVariants;
    }

    @Override
    protected void attachMethod(JsonElement jsonElement, final JComponent component, final SwingsonGui gui, String propertyName, final MethodExecutor mExecutor, final int methodArgumentVariant, final ConditionAndAction conditionAndAction) {
        EventExecutor<KeyEvent> executor = new EventExecutor<KeyEvent>() {
            @Override
            public void execute(KeyEvent event) {
                if (!Swingson.isEnabledUserInput()) {
                    return;
                }
                try {
                    switch (methodArgumentVariant) {
                        case 0:
                            mExecutor.invoke(event.getKeyChar());
                            break;
                        case 1:
                            mExecutor.invoke(event.getKeyChar(), event.getKeyCode());
                            break;
                        case 2:
                            mExecutor.invoke(event.getKeyChar(), event.getKeyCode(), event.getModifiersEx());
                            break;
                        case 3:
                            mExecutor.invoke(event);
                            break;
                    }
                    runAction(conditionAndAction, gui, component);
                } catch (Throwable ex) {
                    onError(gui, ex);
                }
            }
        };
        for (KeyListener listener : component.getKeyListeners()) {
            if (listener instanceof KeyListenerWrapper) {
                KeyListenerWrapper lw = (KeyListenerWrapper) listener;
                switch (propertyName) {
                    case keyPressed:
                        lw.setKeyPressed(executor);
                        break;
                    case keyTyped:
                        lw.setKeyTyped(executor);
                        break;
                    case keyReleased:
                        lw.setKeyReleased(executor);
                        break;
                }
                return;
            }
        }

        KeyListenerWrapper listener = new KeyListenerWrapper();
        switch (propertyName) {
            case keyPressed:
                listener.setKeyPressed(executor);
                break;
            case keyTyped:
                listener.setKeyTyped(executor);
                break;
            case keyReleased:
                listener.setKeyReleased(executor);
                break;
        }

        component.addKeyListener(listener);
    }

    private static class KeyListenerWrapper implements KeyListener {

        private EventExecutor<KeyEvent> keyTyped;
        private EventExecutor<KeyEvent> keyPressed;
        private EventExecutor<KeyEvent> keyReleased;

        public void setKeyTyped(EventExecutor<KeyEvent> keyTyped) {
            this.keyTyped = keyTyped;
        }

        public void setKeyPressed(EventExecutor<KeyEvent> keyPressed) {
            this.keyPressed = keyPressed;
        }

        public void setKeyReleased(EventExecutor<KeyEvent> keyReleased) {
            this.keyReleased = keyReleased;
        }

        @Override
        public void keyTyped(KeyEvent e) {
            if (keyTyped != null) {
                keyTyped.execute(e);
            }
        }

        @Override
        public void keyPressed(KeyEvent e) {
            if (keyPressed != null) {
                keyPressed.execute(e);
            }
        }

        @Override
        public void keyReleased(KeyEvent e) {
            if (keyReleased != null) {
                keyReleased.execute(e);
            }
        }
    }

}
